using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Text;
namespace ICSharpCode.TextEditor.Document
{
    public class SelectionManager : IDisposable
    {
        private TextLocation selectionStart;
        private IDocument document;
        private TextArea textArea;
        internal SelectFrom selectFrom = new SelectFrom();
        internal List<ISelection> selectionCollection = new List<ISelection>();
        public event EventHandler SelectionChanged;
        internal TextLocation SelectionStart
        {
            get
            {
                return this.selectionStart;
            }
            set
            {
                this.selectionStart = value;
            }
        }
        public List<ISelection> SelectionCollection
        {
            get
            {
                return this.selectionCollection;
            }
        }
        public bool HasSomethingSelected
        {
            get
            {
                return this.selectionCollection.Count > 0;
            }
        }
        public bool SelectionIsReadonly
        {
            get
            {
                if(this.document.ReadOnly)
                {
                    return true;
                }
                foreach(ISelection current in this.selectionCollection)
                {
                    if(SelectionManager.SelectionIsReadOnly(this.document, current))
                    {
                        return true;
                    }
                }
                return false;
            }
        }
        public string SelectedText
        {
            get
            {
                StringBuilder stringBuilder = new StringBuilder();
                foreach(ISelection current in this.selectionCollection)
                {
                    stringBuilder.Append(current.SelectedText);
                }
                return stringBuilder.ToString();
            }
        }
        internal static bool SelectionIsReadOnly(IDocument document, ISelection sel)
        {
            if(document.TextEditorProperties.SupportReadOnlySegments)
            {
                return document.MarkerStrategy.GetMarkers(sel.Offset, sel.Length).Exists((TextMarker m) => m.IsReadOnly);
            }
            return false;
        }
        public SelectionManager(IDocument document)
        {
            this.document = document;
            document.DocumentChanged += new DocumentEventHandler(this.DocumentChanged);
        }
        public SelectionManager(IDocument document, TextArea textArea)
        {
            this.document = document;
            this.textArea = textArea;
            document.DocumentChanged += new DocumentEventHandler(this.DocumentChanged);
        }
        public void Dispose()
        {
            if(this.document != null)
            {
                this.document.DocumentChanged -= new DocumentEventHandler(this.DocumentChanged);
                this.document = null;
            }
        }
        private void DocumentChanged(object sender, DocumentEventArgs e)
        {
            if(e.Text == null)
            {
                this.Remove(e.Offset, e.Length);
                return;
            }
            if(e.Length < 0)
            {
                this.Insert(e.Offset, e.Text);
                return;
            }
            this.Replace(e.Offset, e.Length, e.Text);
        }
        public void SetSelection(ISelection selection)
        {
            if(selection == null)
            {
                this.ClearSelection();
                return;
            }
            if(this.SelectionCollection.Count == 1 && selection.StartPosition == this.SelectionCollection[0].StartPosition && selection.EndPosition == this.SelectionCollection[0].EndPosition)
            {
                return;
            }
            this.ClearWithoutUpdate();
            this.selectionCollection.Add(selection);
            this.document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, selection.StartPosition.Y, selection.EndPosition.Y));
            this.document.CommitUpdate();
            this.OnSelectionChanged(EventArgs.Empty);
        }
        public void SetSelection( int startColumn, int endColumn,int line)
        {
            this.SetSelection(startColumn, line, endColumn, line);
        }
        public void SetSelection(int startColumn, int startLine, int endColumn, int endLine)
        {
            this.SetSelection(new TextLocation(startColumn, startLine), new TextLocation(endColumn, endLine));
        }
        public void SetSelection(TextLocation startPosition, TextLocation endPosition)
        {
            this.SetSelection(new DefaultSelection(this.document, startPosition, endPosition));
        }
        public bool GreaterEqPos(TextLocation p1, TextLocation p2)
        {
            return p1.Y > p2.Y || (p1.Y == p2.Y && p1.X >= p2.X);
        }
        public void ExtendSelection(TextLocation oldPosition, TextLocation newPosition)
        {
            if(oldPosition == newPosition)
            {
                return;
            }
            int x = newPosition.X;
            bool flag = this.GreaterEqPos(oldPosition, newPosition);
            TextLocation textLocation;
            TextLocation textLocation2;
            if(flag)
            {
                textLocation = newPosition;
                textLocation2 = oldPosition;
            }
            else
            {
                textLocation = oldPosition;
                textLocation2 = newPosition;
            }
            if(textLocation == textLocation2)
            {
                return;
            }
            if(!this.HasSomethingSelected)
            {
                this.SetSelection(new DefaultSelection(this.document, textLocation, textLocation2));
                if(this.selectFrom.where == 0)
                {
                    this.SelectionStart = oldPosition;
                }
                return;
            }
            ISelection selection = this.selectionCollection[0];
            if(textLocation == textLocation2)
            {
                return;
            }
            if(this.selectFrom.where == 1)
            {
                newPosition.X = 0;
            }
            if(this.GreaterEqPos(newPosition, this.SelectionStart))
            {
                selection.StartPosition = this.SelectionStart;
                if(this.selectFrom.where == 1)
                {
                    selection.EndPosition = new TextLocation(this.textArea.Caret.Column, this.textArea.Caret.Line);
                }
                else
                {
                    newPosition.X = x;
                    selection.EndPosition = newPosition;
                }
            }
            else
            {
                if(this.selectFrom.where == 1 && this.selectFrom.first == 1)
                {
                    selection.EndPosition = this.NextValidPosition(this.SelectionStart.Y);
                }
                else
                {
                    selection.EndPosition = this.SelectionStart;
                }
                selection.StartPosition = newPosition;
            }
            this.document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, textLocation.Y, textLocation2.Y));
            this.document.CommitUpdate();
            this.OnSelectionChanged(EventArgs.Empty);
        }
        public TextLocation NextValidPosition(int line)
        {
            if(line < this.document.TotalNumberOfLines - 1)
            {
                return new TextLocation(0, line + 1);
            }
            return new TextLocation(this.document.GetLineSegment(this.document.TotalNumberOfLines - 1).Length + 1, line);
        }
        private void ClearWithoutUpdate()
        {
            while(this.selectionCollection.Count > 0)
            {
                ISelection selection = this.selectionCollection[this.selectionCollection.Count - 1];
                this.selectionCollection.RemoveAt(this.selectionCollection.Count - 1);
                this.document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, selection.StartPosition.Y, selection.EndPosition.Y));
                this.OnSelectionChanged(EventArgs.Empty);
            }
        }
        public void ClearSelection()
        {
            Point mousepos = this.textArea.mousepos;
            this.selectFrom.first = this.selectFrom.where;
            TextLocation logicalPosition = this.textArea.TextView.GetLogicalPosition(mousepos.X - this.textArea.TextView.DrawingPosition.X, mousepos.Y - this.textArea.TextView.DrawingPosition.Y);
            if(this.selectFrom.where == 1)
            {
                logicalPosition.X = 0;
            }
            if(logicalPosition.Line >= this.document.TotalNumberOfLines)
            {
                logicalPosition.Line = this.document.TotalNumberOfLines - 1;
                logicalPosition.Column = this.document.GetLineSegment(this.document.TotalNumberOfLines - 1).Length;
            }
            this.SelectionStart = logicalPosition;
            this.ClearWithoutUpdate();
            this.document.CommitUpdate();
        }
        public void RemoveSelectedText()
        {
            if(this.SelectionIsReadonly)
            {
                this.ClearSelection();
                return;
            }
            List<int> list = new List<int>();
            int num = -1;
            bool flag = true;
            foreach(ISelection current in this.selectionCollection)
            {
                if(flag)
                {
                    int y = current.StartPosition.Y;
                    if(y != current.EndPosition.Y)
                    {
                        flag = false;
                    }
                    else
                    {
                        list.Add(y);
                    }
                }
                num = current.Offset;
                this.document.Remove(current.Offset, current.Length);
            }
            this.ClearSelection();
            if(num != -1)
            {
                if(flag)
                {
                    using(List<int>.Enumerator enumerator2 = list.GetEnumerator())
                    {
                        while(enumerator2.MoveNext())
                        {
                            int current2 = enumerator2.Current;
                            this.document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, current2));
                        }
                        goto IL_FB;
                    }
                }
                this.document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
            IL_FB:
                this.document.CommitUpdate();
            }
        }
        private bool SelectionsOverlap(ISelection s1, ISelection s2)
        {
            return (s1.Offset <= s2.Offset && s2.Offset <= s1.Offset + s1.Length) || (s1.Offset <= s2.Offset + s2.Length && s2.Offset + s2.Length <= s1.Offset + s1.Length) || (s1.Offset >= s2.Offset && s1.Offset + s1.Length <= s2.Offset + s2.Length);
        }
        public bool IsSelected(int offset)
        {
            return this.GetSelectionAt(offset) != null;
        }
        public ISelection GetSelectionAt(int offset)
        {
            foreach(ISelection current in this.selectionCollection)
            {
                if(current.ContainsOffset(offset))
                {
                    return current;
                }
            }
            return null;
        }
        internal void Insert(int offset, string text)
        {
        }
        internal void Remove(int offset, int length)
        {
        }
        internal void Replace(int offset, int length, string text)
        {
        }
        public ColumnRange GetSelectionAtLine(int lineNumber)
        {
            foreach(ISelection current in this.selectionCollection)
            {
                int y = current.StartPosition.Y;
                int y2 = current.EndPosition.Y;
                if(y < lineNumber && lineNumber < y2)
                {
                    ColumnRange result = ColumnRange.WholeColumn;
                    return result;
                }
                if(y == lineNumber)
                {
                    LineSegment lineSegment = this.document.GetLineSegment(y);
                    int x = current.StartPosition.X;
                    int endColumn = (y2 == lineNumber) ? current.EndPosition.X : (lineSegment.Length + 1);
                    ColumnRange result = new ColumnRange(x, endColumn);
                    return result;
                }
                if(y2 == lineNumber)
                {
                    int x2 = current.EndPosition.X;
                    ColumnRange result = new ColumnRange(0, x2);
                    return result;
                }
            }
            return ColumnRange.NoColumn;
        }
        public void FireSelectionChanged()
        {
            this.OnSelectionChanged(EventArgs.Empty);
        }
        protected virtual void OnSelectionChanged(EventArgs e)
        {
            if(this.SelectionChanged != null)
            {
                this.SelectionChanged(this, e);
            }
        }
    }
}
